package com.aeoncredit.fep.core.adapter.brand.utils;

import org.jpos.iso.ISOUtil;
import org.jpos.iso.header.BaseHeader;

/*
 * BASE1 Header
 * <pre>
 *   0 hlen;         Fld  1: Header Length        1B      (Byte     0)
 *   1 hformat;      Fld  2: Header Format        8N,bit  (Byte     1)
 *   2 format;       Fld  3: Text Format          1B      (Byte     2)
 *   3 len[2];       Fld  4: Total Message Length 2B      (Byte  3- 4)
 *   5 dstId[3];     Fld  5: Destination Id       6N,BCD  (Byte  5- 7)
 *   8 srcId[3];     Fld  6: Source Id            6N,BCD  (Byte  8-10)
 *  11 rtCtl;        Fld  7: Round-Trip Ctrl Info 8N,bit  (Byte    11)
 *  12 flags[2];     Fld  8: BASE I Flags        16N,bit  (Byte 12-13)
 *  14 status[3];    Fld  9: Message Status Flags 24bits  (Byte 14-16)
 *  17 batchNbr;     Fld 10: Batch Number        1B       (Byte    17)
 *  18 reserved[3];  Fld 11: Reserved            3B       (Byte 18-20)
 *  21 userInfo;     Fld 12: User Info           1B       (Byte    21)
 *  The following fields are only presend in a reject message
 *  22 bitmap;       Fld 13: Bitmap              2B       (Byte 22-23)
 *  24 rejectdata;   Fld 14: Reject Data Group   2B       (Byte 24-25)
 * </pre>
 *
 */
public class Base1Header extends BaseHeader {
	
	private static final long serialVersionUID = -2758401868293287434L;
	
	/** Normal Header Length */
	public static final int NORMALLENGTH = 22;
	
	/** Used for Reject Header */
	private Base1Header rejectHeader = null;

	/**
	 * Create a empty header using all 0.<br>
	 * */
    public Base1Header() {
        this("000000", "000000");
    }// end of Base1Header
    
    /**
     * Create a normal header using the source and the destination.<br>
     * 
     * @param String - source
     * @param String - destination
     * */
    public Base1Header(String source, String destination) {
        super();
        header = new byte[NORMALLENGTH];
        header[0] = NORMALLENGTH;
        setHFormat(1);
        setFormat(2);
        setSource(source);
        setDestination(destination);
        setRtCtl(0);
        setFlags(0);
        setStatus(0);
        setBatchNumber(0);
        setReserved(0);
        setUserinfo(0);
        
    }// end of constructor
    
    /**
     * Create a header using byte array.<br>
     * If the length of the byte array is 48, it will create a reject header inside it.<br>
     * 
     * @param byte[] - header
     */
    public Base1Header(byte[] header) {
    	
        super(header);

		if(header!=null && header.length == 48){
			// create the common header 
			byte[] comHeader = new byte[22];
			System.arraycopy(header, 26, comHeader, 0, 22);
			this.header = comHeader;
			
			// create the reject header 
			byte[] rejHeader = new byte[26];
			System.arraycopy(header, 0, rejHeader, 0, 26);
			rejectHeader = new Base1Header(rejHeader);
		}
    }// end of Base1Header

    public int unpack(byte[] header) {
        this.header = header;
        return header.length;
    }// end of unpack
    
    public int getHLen() {
        return (int) (header[0] & 0xFF);
    }// end of getHLen
    
    public void setHFormat(int hformat) {
        header[1] = (byte) hformat;
    }// end of setHFormat
    
    public int getFormat() {
        return (int) (header[2] & 0xFF);
    }// end of getFormat
    
    public void setRtCtl(int i) {
        header[11] = (byte) i;
    }// end of setRtCtl
    
    public void setFlags(int i) {
        header[12] = (byte) ((i >> 8) & 0xFF);
        header[13] = (byte) (i & 0xFF);
    }// end of setFlags
    
    public void setStatus(int i) {
        header[14] = (byte) ((i >> 16) & 0xFF);
        header[15] = (byte) ((i >> 8) & 0xFF);
        header[16] = (byte) (i & 0xFF);
    }// end of setStatus
    
    public void setBatchNumber(int i) {
        header[17] = (byte) (i & 0xFF);
    }// end of setBatchNumber
    
    public void setFormat(int format) {
        header[2] = (byte) format;
    }// end of setFormat
    
    public void setLen(int len) {
        len += header.length;
        header[3]  = (byte) ((len >> 8) & 0xff);
        header[4]  = (byte) (len        & 0xff);
    }// end of setLen
    
    public void setDestination(String dest) {
        byte[] d = ISOUtil.str2bcd(dest, true);
        System.arraycopy(d, 0, header, 5, 3);
    }// end of setDestination
    
    public void setSource(String src) {
        byte[] d = ISOUtil.str2bcd(src, true);
        System.arraycopy(d, 0, header, 8, 3);
    }// end of setSource
    
    public String getSource() {
        return ISOUtil.bcd2str (this.header, 8, 6, false);
    }// end of getSource
    
    public String getDestination() {
        return ISOUtil.bcd2str (this.header, 5, 6, false);
    }// end of getDestination
    
    public void swapDirection() {
        if (header != null && header.length >= NORMALLENGTH) {
            byte[] source = new byte[3];
            System.arraycopy(header, 8, source, 0, 3);
            System.arraycopy(header, 5, header, 8, 3);
            System.arraycopy(source, 0, header, 5, 3);
        }
    }// end of swapDirection
    
    public boolean isRejected() {
        // Header length must be 26 or gerater
        // And header field 13 bit 1 must be 1 (field 13 starts at byte 22)
    	return (null != rejectHeader) && (rejectHeader.getLength() >= 26) && ((rejectHeader.header[22] & 0x80) == 0x80);
    }// end of isRejected
    
    public boolean isUndeliverable(){
    	// Header field 9 bit 9 must be 1
    	return (null != header) && (null == rejectHeader) && ((header[16] & 0x80)) == 0x80;
    }// end of isUndeliverable
	
    public String getRejectCode() {
        return isRejected() ? ISOUtil.bcd2str (this.header, 24, 4, false) : "";
    }// end of getRejectCode
    
    public void setHLen(int hlen) {
        header[0] = (byte)hlen;
    }// end of setHLen
    
	public int getHFormat() {
        return (int) (header[1] & 0xFF);
    }// end of getHFormat
	
	public int getLen() {
        int highValue = (int) (header[3] & 0xFF);
        int lowValue = (int) (header[4] & 0xFF);
        return (highValue << 8) + lowValue;
    }// end of getLen
	
	public int getRtCtl() {
        return (int) (header[11] & 0xFF);
    }// end of getRtCtl
	
	public int getFlags() {
        int highValue = (int) (header[12] & 0xFF);
        int lowValue = (int) (header[13] & 0xFF);
        return (highValue << 8) + lowValue;
    }// end of getFlags
	
	public int getStatus() {
        int highValue = (int) (header[14] & 0xFF);
        int midValue = (int) (header[15] & 0xFF);
        int lowValue = (int) (header[16] & 0xFF);
        return (highValue << 16) + (midValue << 8) + lowValue;
    }// end of getStatus
	
	public int getBatchNumber() {
        return (int) (header[17] & 0xFF);
    }// end of getBatchNumber
	
	public void setReserved(int Reserved) {
        header[18]  = (byte) ((Reserved >> 16) & 0xFF);
        header[19]  = (byte) ((Reserved >> 8) & 0xFF);
        header[20]  = (byte) ( Reserved  & 0xFF);
    }// end of setReserved
	
	public int getReserved() {
        int highValue = (int) (header[18] & 0xFF);
        int midValue = (int) (header[19] & 0xFF);
        int lowValue = (int) (header[20] & 0xFF);
        return (highValue << 16) + (midValue << 8) + lowValue;
    }// end of getReserved
	
	public int getUserinfo() {
        return (int) (header[21] & 0xFF);
    }// end of getUserinfo
	
	public void setUserinfo(int Userinfo) {
        header[21]  = (byte) ( Userinfo  & 0xFF);
    }// end of setUserinfo
	
	public int getHeaderfieldAcount(){
		return 12;
	}// end of getHeaderfieldAcount
	
	public int getHBitMap() {
        int highValue = (int) (header[22] & 0xFF);
        int lowValue = (int) (header[23] & 0xFF);
        return (highValue << 8) + lowValue;
    }// end of getHBitMap
	
	public void setHBitMap(int i) {
        header[22] = (byte) ((i >> 8) & 0xFF);
        header[23] = (byte) (i & 0xFF);
    }// end of setHBitMap
	
    public void setRejectCode(String src) {
        byte[] d = ISOUtil.str2bcd(src, true);
        System.arraycopy(d, 0, header, 24, 2);
    }// end of setRejectCode

	public Base1Header getRejectHeader() {
		return rejectHeader;
	}// getRejectHeader

	public void setRejectHeader(Base1Header rejectHeader) {
		this.rejectHeader = rejectHeader;
	}// end of setRejectHeader
	
}// end of class
